package jamun

import java.io._

object Main {
  val configLocation = "etc/jamunConf.xml"

  lazy val config = Props(configLocation)

  def main(args:Array[String]) = {
    if (args.length == 0) showHelp
    else {
      val cmd = args(0)

      val cmdFunc = findCmdDetail(cmd)

      if (cmdFunc.isDefined)
        cmdFunc.get.apply(args slice (1, args.length))
      else println("Command not recognized: " + cmd)
    }
  }

  private def findCmdDetail(name:String) = cmdMap find (_.name == name)

  val listCmdDetail      = Cmd ("list",    listCmd,    "List <specified> packages. specified is one of [installed, available]")
  val infoCmdDetail      = Cmd ("info",    infoCmd,    "Information for a given package")
  val installCmdDetail   = Cmd ("install", installCmd, "Install specified package(s)")
  val updateCmdDetail    = Cmd ("update",  updateCmd,  "Update specified package(s)")

  private val cmdMap = List (listCmdDetail, infoCmdDetail, installCmdDetail, updateCmdDetail)

  def showHelp = {
    println ("jamun <command> <command-specific-options>")
    println ("\ncommands:")
    cmdMap foreach (c => println("  " + c.name + "\n    " + c.descr + "\n"))
  }

  def showCmdHelp(cmd:Cmd) = {
    println("Arguments for " + cmd.name + " were not specified correctly")
    println("Help for " + cmd.name + ":")
    println("   " + cmd.descr)
  }

  def wild2regex(s:String) = (s replace ("*", ".*")) replace ("?", ".")

  def listCmd(args:Array[String]):Unit = {
    def showListHelp = showCmdHelp(listCmdDetail)

    if (args.length > 0) {
      val lstType = args(0)
      if (lstType == "installed") {

        val filtered = if (args.length > 1) {
          // filter specified
          InstalledPkgs.list filter (p => p.name matches (wild2regex(args(1))))
        } else {
          InstalledPkgs.list
        }

        println ("Installed packages:")
        val strFrmt = "%-30s  %-10s  %-15s"
        println (String.format(strFrmt,"Name","Version","Revision"))
        println (String.format(strFrmt,"----","-------","--------"))
        filtered foreach (p => println (String.format(strFrmt,p.name,p.version, p.revision)))

      } else if (lstType == "available") {
        val mngd = if (args.length > 1) {
          // filter specified
          ManagedPkgs.getFilteredByName(args(1))
        } else {
          ManagedPkgs.getAll
        }

        println ("Available packages:")
        val strFrmt = "%-30s  %-20s  %-20s %-10s"
        println (String.format(strFrmt,"Name","Latest version", "Installed ver", "Repository"))
        println (String.format(strFrmt,"----","--------------", "-------------", "----------"))
        mngd foreach {mp =>
          val instPkg = InstalledPkgs.map get (mp.name)
          val instInfo = if (instPkg.isDefined) {
            instPkg.get.version + "-" + instPkg.get.revision
          } else {
            ""
          }
          println (String.format(strFrmt,mp.name,mp.version+"-"+mp.release, instInfo, mp.repo.get.name))
        }
      } else if (lstType == "all") {
        val filtered:List[MngdPackage] = if (args.length > 1) {
          // filter specified
          ManagedPkgs.getFilteredByName(args(1))
        } else {
          ManagedPkgs.getAll
        }

        println ("All packages:")
        val strFrmt = "%-30s  %-20s"
        println (String.format(strFrmt,"Name","Version"))
        println (String.format(strFrmt,"----","-------"))
        filtered foreach (p => println (String.format(strFrmt,p.name,p.version+"-"+p.release)))
      } else showListHelp
        
    } else showListHelp
  }

  def infoCmd(args:Array[String]) = {
  }

  // lazy val availablePkgs = ManagedPkgs.list filter (m => (InstalledPkgs.list forall (i => i.name != m.name)))
  // lazy val availableMap = Map((ManagedPkgs.list map (p => (p.name, p))) : _*)

  def installCmd(args:Array[String]) = {
    def notInstalled(pname:String) = (! InstalledPkgs.map.isDefinedAt(pname))
    val markedPkgs = args flatMap (a =>
      ManagedPkgs.getFilteredByName(a) filter (p => notInstalled(p.name))
    )
    println ("Marked packages:")
    val strFrmt = "%-30s  %-10s"
    println (String.format(strFrmt,"Name","Version"))
    println (String.format(strFrmt,"----","-------"))
    markedPkgs foreach (p => println (String.format(strFrmt,p.name,p.version)))

    val dependents = Dependency.getFor(markedPkgs)
    println(dependents)
  }

  def updateCmd(args:Array[String]) = {
  }

  case class Cmd(name:String, f : (Array[String]) => Unit, descr : String) {
    def apply(a:Array[String]) = f(a)
  }

}

case class Props (file:String) {
  val core = new java.util.Properties
  core.loadFromXML (new FileInputStream (file))

  def apply (s:String) = core.getProperty(s)
}
